package Plug;

use strict;

use base qw (NetworkDB);

use Data::Dumper;

use NetAddr::IP;
use Logger;
use Host;

__PACKAGE__->set_up_table('plugs');
__PACKAGE__->has_many(addresses => 'Host');	# convention violence: class named Host, not Address
__PACKAGE__->has_a(switchid => 'Switch');
__PACKAGE__->has_a(segmentid => 'Segment');
#__PACKAGE__->has_a(acl_set_id => 'ACL::Sets');

my ($time_before, $time_after);

sub initialize {

}

sub update_address2plug_assignments {
# aktualizuje priradenia adries zasuvkam v databaze podla aktualnych adries zapamatanych na porte 
	my $self = shift;
	my $unit = $self->switchid->unit;
	my $segment = $self->segmentid;
        my @macs = @_; 
	my @verified_hosts;
        foreach (@macs) {
		my $mac = $_;
		my $ip;
                if ($ip = $segment->MAC2IP($mac)) {	# zistenie IP adresy pre kazdu MAC
			if (!$ip) {             # MAC nema zaznam v Arpwatch - ignore 
			} elsif ($ip eq -1) {   # MAC ma inu IP, nez by mala mat - ignore
			} elsif (Network->verify_address_assignment($mac,$ip)) {
                      		push @verified_hosts, { mac => $mac, ip => $ip };	# zapis do objektu
			} else { }
                 }
         }

	my $plugid = $self->plugid;
	my $is_activated = $self->is_activated;
	$self->unbindIPs();		# zrus pre nu vsetky relacie s IP adresami
	$is_activated = 'false';		# ak nebude mat povolene IPcky, tak je deaktivovana
	# nastav databazu
	foreach my $host (@verified_hosts) {
		$is_activated='true';		# ak je aspon 1 host zaznam, zas. aktiv.
		
		# objekt - riadok z tabulky addresses
		my $address = Host->search({ ip => $host->{ip} })->next;
		# deaktivuj ine aktivovane zasuvky IP adries, ktore budu priradene tejto aktivovanej
		if (defined $address->plugid && $address->plugid->plugid > 0) {
			my $preserved_plugid = $address->plugid->plugid;
			$address->plugid->update_address2plug_assignments();
			my $undeleted_plug = Plug->retrieve($preserved_plugid);
			$undeleted_plug->configure_interface;
		} 
		$address->mac($host->{mac});		# nastav MAC adresu objektu
		$address->plugid($self->plugid);	# nastav cislo zasuvky
		$address->update;			# zapis do databazy
		push @{$self->{hosts}}, $host;		# zapis do objektu, kvoli vracaniu XML
	}
	$self->is_activated($is_activated);	#	nastav flag, ci je zasuvka aktivovana, alebo nie?
	$self->update;				#	zapis do databazy
}

sub configure_interface {
	my $self = shift;
	my $unit = $self->switchid->unit;
	my $port = $self->port;
	my $stack = $self->switchid->stackid;
	my $stack_name = $stack->hostname;
      	Logger->write(__PACKAGE__." Setting switchport $port of unit $unit of $stack_name according to database . . .");
#	if ($self->is_vlan_trunk) {
#		$stack->set_switchport_broadcast_max_bitrate($unit,$port,0);
#		#TODO: generovanie popisu uplinkovych portov podla uplink_pair
#		return '';
#	} else {
#		my $BSC = $self->broadcast_max_bitrate;
#		$stack->set_switchport_broadcast_max_bitrate($unit,$port,$BSC);
#		my $description = $self->building."-".$self->block." ".$self->room."/".$self->label;
#		$stack->set_switchport_description($unit,$port,$description);
#	}
	
	my @associated_hosts = Host->search({plugid => $self->plugid});
	my (@allowed_sources, @allowed_destinations, $vlan_id);
	if ($self->segmentid) {
		@allowed_destinations = split /,/,$self->segmentid->allways_allowed_destinations;
		foreach my $host (@associated_hosts) {
			push @allowed_sources, $host->ip;
		}
		$vlan_id = $self->segmentid->segmentid;
	}

	$stack->unbind_extended_IPACL($unit,$port,'in');
	$stack->drop_extended_IPACL($unit,$port,'in');
	$stack->IPACL_deny_dhcp_server($unit,$port,'in');
	$stack->IPACL_permit_sources($unit,$port,'in',\@allowed_sources);
	$stack->IPACL_permit_destinations($unit,$port,'in',\@allowed_destinations);
	$stack->bind_extended_IPACL($unit,$port,'in');

	# nastav defaultnu policy na IP ACL
	if ($self->default_deny_all) {
		$stack->IPACL_deny_default($unit,$port,'in');
	}

#	# nastav ostatne parametre: access VLAN, broadcast storm control, popis, max. pocet MAC adries
#	$stack->set_switchport_access_VLAN($unit,$port,$vlan_id);

	my $max_MACs_count = $self->max_macs;
	Logger->write(__PACKAGE__." Switchport $stack_name $unit / $port set.");
}

sub unbindIPs {
	my $self = shift;
	my @bound_addresses = Host->search({ plugid => $self->plugid });
	foreach my $address (@bound_addresses) {
		$address->plugid(0);
		$address->update;
	}
}


sub GetMAClist {
# vstup: ziaden
# vystup: MAC adresy aktualne zapamatane na danom porte
# (a tym padom aj na prislusnej VLANe, kedze kazdy ne-trunkovy port ma nastavenu prave jednu nativnu VLAN)
	my $self = shift;		# plug
	my $switch = $self->switchid;	# switch
	my $stack = $switch->stackid;	# stack
        my $portnum = $stack->detranslatePortNumber($switch->unit, $self->port); # switch type specific
        my @macs = $stack->GetMAClist($portnum, $self->segmentid->segmentid); # zisti vsetky MAC z mac-address-table daneho stohu
        return @macs;
}


sub dump2line {
	my $self = shift;
	return $self->building."-".$self->block." ".$self->room."/".$self->label.", stack ".$self->switchid->stackid.", unit ".$self->switchid->unit." (switch ".$self->switchid."), port ".$self->port.", plugID ".$self->plugid;

}

sub dump2hash {
	my $self = shift;
        my $act_record = {
                        plugid => $self->plugid,
                        letter => $self->label,		# ked zmenia letter->label aj v HDSW, zmenit aj tu
                        room => $self->room,
                        block => $self->block,
                        building => $self->building,
                        stack => $self->switchid->stackid->stackid,
                        switch => $self->switchid->switchid,
                        unit => $self->switchid->unit,
                        port => $self->port,
        };
	foreach my $host (@{$self->{hosts}}) {	# ak bolo nastavene metodou Plug::update_address2plug_assignments()
		push @{$act_record->{hosts}}, $host;
	}
	return $act_record;
}

1;
